#include "socket_private_acl.h"
#include "pfunc.h"
#include "Log.h"
#include "pfunc_print.h"
#include "lib_acl.h"

SocketPrivate_ACL::SocketPrivate_ACL(unsigned int port,std::string ip_/*="0.0.0.0"*/)
	: m_Port(port)
{
	char buf[128] = { 0 };
	sprintf(buf, "%s:%d", ip_.c_str(),m_Port);
	addr = acl::string(buf);
	m_CSockets.clear();
	m_OnListen = false;
	newlinkF = false;
};
SocketPrivate_ACL::~SocketPrivate_ACL() {
	disConnect();
};

int SocketPrivate_ACL::onConnect()
{
	//acl::acl_cpp_init();
	if (m_SSocket.open(addr) == false)
	{
		Print_WARN("open %s error %s\r\n", addr.c_str(), acl::last_serror());
		return 0;
	}
	else {
		m_OnListen = true;
		Print_NOTICE("open %s ok\r\n", addr.c_str());
		return 1;
	}
}

void SocketPrivate_ACL::disConnect()
{
	try {
		m_MyMutex.Lock();
		std::map<KeyObj_GClient, ClientSOCKET_ACL>::iterator it = m_CSockets.begin();
		while (it != m_CSockets.end())
		{
			close_client(it->second.client);
#ifdef WIN32
			it = m_CSockets.erase(it);
#else
			std::map<KeyObj_GClient, ClientSOCKET_ACL>::iterator ittemp = it++;
			m_CSockets.erase(ittemp);
#endif
		}
		m_MyMutex.Unlock();
	}
	catch (...)
	{
		CLogger::createInstance()->Log(MsgError,
			"socket deleteCSockets exception: [%s %s %d]!"
			, __FILE__, __FUNCTION__, __LINE__);
	}
	m_OnListen = false;
	if (m_SSocket.close() == false)
	{
		CLogger::createInstance()->Log(MsgError
			, "close %s error", addr.c_str());
	}
}

void SocketPrivate_ACL::close_client(acl::socket_stream* client_acl)
{
	if(NULL==client_acl)
	{
		return;
	}
	if(!client_acl->close())
	{
		CLogger::createInstance()->Log(MsgError
			, "close client_acl error[%d,%s]"
			, acl_last_error()
			, acl::last_serror());
	}
	delete client_acl;
	client_acl = NULL;
}

bool SocketPrivate_ACL::emptyClients()
{
	bool ret = false;
	m_MyMutex.Lock();
	ret = m_CSockets.empty();
	m_MyMutex.Unlock();
	return ret;
}

bool SocketPrivate_ACL::getNewAddClient(std::vector<unsigned long> &ips)
{
	if (!newlinkF)
	{
		return false;
	}
	m_MyMutex.Lock();
	std::map<KeyObj_GClient, ClientSOCKET_ACL>::iterator it = m_CSockets.begin();
	while (it != m_CSockets.end())
	{
		if (it->second.flag <= 0)
		{
			ips.push_back(it->first.m_ip);
			it->second.flag = 1;
		}
		it++;
	}
	m_MyMutex.Unlock();
	newlinkF = false;
	return !ips.empty();
}

int SocketPrivate_ACL::Read(std::map<KeyObj_GClient, RDClient> &bufs)
{
	int re = 0;
	try {
		m_MyMutex.Lock();
		std::map<KeyObj_GClient, ClientSOCKET_ACL>::iterator it = m_CSockets.begin();
		while (it != m_CSockets.end())
		{
			char _buf[512] = { 0 };
			acl::string res;
			int len = it->second.client->read(_buf, 512,false);
			if (len<0)
			{
				int lerror = acl_last_error();
				//win 10060 timeout,linux 110 timeout
				if (lerror != 10060 
					// && lerror !=110 
					&& lerror !=11 
					// && lerror != 0
					)
				{
					CLogger::createInstance()->Log(MsgWarn,
						"socket read data failed[%d,%s]! return val is %d.[%s %s %d]"
						, lerror,acl::last_serror(), len, __FILE__, __FUNCTION__, __LINE__);
					close_client(it->second.client);
#ifdef WIN32
					it = m_CSockets.erase(it);
#else
					std::map<KeyObj_GClient, ClientSOCKET_ACL>::iterator ittemp = it++;
					m_CSockets.erase(ittemp);
#endif
					continue;
				}
			}
			if (len>0)
			{
				re += len;
				std::map<KeyObj_GClient, RDClient>::iterator itrd = bufs.find(it->first);
				if (itrd != bufs.end())
				{
					itrd->second.add((unsigned char*)_buf, len);
				}
				else
				{
					bufs[it->first] = RDClient((unsigned char*)_buf, len);
				}
			}

			it++;
		}
		m_MyMutex.Unlock();

	}
	catch (...)
	{
		CLogger::createInstance()->Log(MsgError,
			"Read Data Failed!unknown error! [%s %s %d]"
			, __FILE__, __FUNCTION__, __LINE__);
		re = -1;
	}
	return re;
}

int SocketPrivate_ACL::Write(const char* buf, int size)
{
	int re = -1;
	try {
		m_MyMutex.Lock();
		std::map<KeyObj_GClient, ClientSOCKET_ACL>::iterator it = m_CSockets.begin();
		while (it != m_CSockets.end())
		{
			re = it->second.client->write(buf, size);
			if (re < 0)
			{
				int lerror = acl_last_error();
				if (lerror != 0)
				{
					//CLogger willadd datetime for log, and the time difference is very small
					CLogger::createInstance()->Log(MsgWarn,
						"socket write data failed! "
						"return val is %d,%s.[%s %s %d]"
						, re, buf
						, __FILE__, __FUNCTION__, __LINE__);
					close_client(it->second.client);
#ifdef WIN32
					it = m_CSockets.erase(it);
#else
					std::map<KeyObj_GClient, ClientSOCKET_ACL>::iterator ittemp = it++;
					m_CSockets.erase(ittemp);
#endif
					continue;
				}
			}
			it++;
		}
		m_MyMutex.Unlock();
	}
	catch (...)
	{
		CLogger::createInstance()->Log(MsgError,
			"Write Data Failed!unknown error![%s %s %d]"
			, __FILE__, __FUNCTION__, __LINE__);
		re = -1;
	}
	return re;
}

int SocketPrivate_ACL::Write(unsigned long ipInt, const char* buf, int size)
{
	int re = -1;
	try {
		m_MyMutex.Lock();
		std::map<KeyObj_GClient, ClientSOCKET_ACL>::iterator it = m_CSockets.find(KeyObj_GClient(ipInt,m_Port));
		if (it != m_CSockets.end())
		{
			re = it->second.client->write(buf, size);
			if (re < 0)
			{
				int lerror = acl_last_error();
				if (lerror != 0)
				{
					//CLogger willadd datetime for log
					CLogger::createInstance()->Log(MsgWarn,
						"socket write data failed! "
						"return val is %d,%s.[%s %s %d]"
						, re, buf
						, __FILE__, __FUNCTION__, __LINE__);
					close_client(it->second.client);
#ifdef WIN32
					it = m_CSockets.erase(it);
#else
					std::map<KeyObj_GClient, ClientSOCKET_ACL>::iterator ittemp = it++;
					m_CSockets.erase(ittemp);
#endif
				}
			}
		}else{
			CLogger::createInstance()->Log(MsgError,
			"client_socket[%lu,%d] isn't find,it may be has deleteed![%s %s %d]"
				, ipInt, m_CSockets.size()
				, __FILE__, __FUNCTION__, __LINE__);
		}
		m_MyMutex.Unlock();
	}
	catch (...)
	{
		CLogger::createInstance()->Log(MsgError,
			"Write Data Failed!unknown error![%s %s %d]"
			, __FILE__, __FUNCTION__, __LINE__);
		re = -1;
	}
	return re;
}

bool SocketPrivate_ACL::Accept()
{
	if (!m_OnListen)
		return false;
	acl::socket_stream* client = m_SSocket.accept();
	if (client != NULL)
	{
		#ifdef WIN32
		SOCKET sock_fd = client->sock_handle();
		int nNetTimeout = 10; //10毫秒
		setsockopt(sock_fd, SOL_SOCKET, SO_SNDTIMEO, (char *)&nNetTimeout, sizeof(int));
		setsockopt(sock_fd, SOL_SOCKET, SO_RCVTIMEO, (char *)&nNetTimeout, sizeof(int));
		#else
		client->set_tcp_non_blocking(true);
		// client->set_tcp_nodelay(true);
		// client->set_rw_timeout(1);
		#endif
		ClientSOCKET_ACL newLink;
		newLink.client = client;
		newLink.flag = 0;
		KeyObj_GClient _linkInfo(pyfree::ipToInt(std::string(client->get_peer_ip())),m_Port);
		m_MyMutex.Lock();
		//每个ip只允许一个连接进来，因此有新进来的连接,主动踢掉旧连接,也防止旧连接已经锻炼,但还没检测出来
		std::map<KeyObj_GClient, ClientSOCKET_ACL>::iterator it_client = m_CSockets.find(_linkInfo);
		if(it_client!=m_CSockets.end()){
			close_client(it_client->second.client);
		}
		m_CSockets[_linkInfo] = newLink;//
		m_MyMutex.Unlock();
		newlinkF = true;
		CLogger::createInstance()->Log(MsgInfo,
			"Connect Accept Success: %s[%llu],[%s %s %d]"
			, client->get_peer(true),_linkInfo.m_ip, __FILE__, __FUNCTION__, __LINE__);
		return true;
	}
	return false;
}

//
//void SocketPrivate_ACL::routeLinkInfo()
//{
//	m_MyMutex.Lock();
//	for (std::map<KeyObj_GClient, SOCKET>::iterator it = m_CSockets.begin(); it != m_CSockets.end(); it++)
//	{
//		addLinkFlag(it->first);
//		//KeyObj_GClient _linkInfo = it->first;
//		//_linkInfo.linkFlag = 1;
//		//addLinkFlag(_linkInfo);
//	}
//	m_MyMutex.Unlock();
//}

void SocketPrivate_ACL::addLinkFlag(KeyObj_GClient it)
{
	m_MyMutexLink.Lock();
	m_CSocketLinks.push(it);
	m_MyMutexLink.Unlock();
}

bool SocketPrivate_ACL::pop(KeyObj_GClient &it)
{
	bool ret = false;
	m_MyMutexLink.Lock();
	if (!m_CSocketLinks.empty())
	{
		it = m_CSocketLinks.front();
		m_CSocketLinks.pop();
		ret = true;
	}
	m_MyMutexLink.Unlock();
	return ret;
}

void SocketPrivate_ACL::routClientLinkState()
{
	unsigned int m_CurTime_UI = static_cast<unsigned int>(time(NULL));
	if (m_RoutCheck_UI < m_CurTime_UI)
	{
		m_RoutCheck_UI = m_CurTime_UI + 60;
		m_MyMutex.Lock();
		for (std::map<KeyObj_GClient, ClientSOCKET_ACL>::iterator it = m_CSockets.begin();it!= m_CSockets.end();it++)
		{
			KeyObj_GClient _linkInfo = it->first;
			_linkInfo.linkFlag = 0;
			addLinkFlag(_linkInfo);
		}
		m_MyMutex.Unlock();
	}
};
